/*
 * Postmore - a pop3 supported mailing list server;
 * Copyright (C) 2010 Peng Lei, pyp125@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 
 * details.
 *
 * You should have received a copy of the GNU Public License along with this
 * program. If not, see http://www.gnu.org/licenses/.
 */

#include "pm.exe.h"
#include "pmstr.h"

/* Initalized an authorization bundle; */
int init_atbd(ATBD* info,const char* name,const char* mail,const char* hostname,int port,const char* username,const char* password)
{
	struct hostent* host;
	if(!(host=gethostbyname(hostname)))
		return -1;
	char username_base64[96];
	char password_base64[96];
	bzero(username_base64,sizeof(username_base64));
	bzero(password_base64,sizeof(password_base64));
	base64(username,username_base64);
	base64(password,password_base64);
	bzero(info->at_name,sizeof(info->at_name));
	bzero(info->at_mail,sizeof(info->at_mail));
	bzero(info->at_hostname,sizeof(info->at_hostname));
	bzero(info->at_address,sizeof(info->at_address));
	bzero(info->at_username,sizeof(info->at_username));
	bzero(info->at_password,sizeof(info->at_password));
	bzero(info->at_username_base64,sizeof(info->at_username_base64));
	bzero(info->at_password_base64,sizeof(info->at_password_base64));
	info->at_port=port;
	strncpy(info->at_name,name,sizeof(info->at_name));
	strncpy(info->at_mail,mail,sizeof(info->at_mail));
	strncpy(info->at_hostname,hostname,sizeof(info->at_hostname));
	strncpy(info->at_username,username,sizeof(info->at_username));
	strncpy(info->at_password,password,sizeof(info->at_password));
	strncpy(info->at_username_base64,username_base64,sizeof(info->at_username_base64));
	strncpy(info->at_password_base64,password_base64,sizeof(info->at_password_base64));
	char address[128];
	inet_ntop(AF_INET,host->h_addr,address,sizeof(address));
	strncpy(info->at_address,address,sizeof(info->at_address));
	return 0;
}

/* Mail operations; */
int mail_init(const char* p)
{
	if(!p)
		return -1;
	strcpy(_m_file,p);
	return 0;
}

int mail_get(int* n, int* s)
{
	FILE* _f_m;
	if(!(_f_m=fopen(_m_file,"r")))
	   return -1;
	int rt=0;
	fscanf(_f_m,"%d|%d",n,s);
	fclose(_f_m);
	return rt;
}

int mail_set(int n, int s)
{
	FILE* _f_m;
	if(!(_f_m=fopen(_m_file,"w+")))
		return -1;
	if(fprintf(_f_m,"%d|%d",n,s)<0)
	{
		fclose(_f_m);
		return -1;
	}
	fclose(_f_m);
	return 0;
}
/* TCP Socket functions; */
int tcp_init(int* st)
{
	if((*st=socket(PF_INET,SOCK_STREAM,0))<0)
	{
		pmlog(strerror(errno));
		return -1;
	}
	return 0;
}

int tcp_connect(int st,ATBD* info)
{
	struct sockaddr_in sa;
	sa.sin_family=AF_INET;
	sa.sin_port=htons(info->at_port);
	sa.sin_addr.s_addr=inet_addr(info->at_address);
	inet_pton(AF_INET,info->at_address,&sa.sin_addr);
	if(connect(st,(struct sockaddr*)&sa,sizeof(struct sockaddr_in))<0)
	{
		pmlog(strerror(errno));
		return -1;
	}
	return 0;
}

int tcp_bind(int st,int port)
{
	struct sockaddr_in sa;
	sa.sin_family=AF_INET;
	sa.sin_port=htons(port);
	sa.sin_addr.s_addr=htonl(INADDR_ANY);
	if(bind(st,(struct sockaddr*)&sa,sizeof(struct sockaddr_in))<0)
	{
		pmlog(strerror(errno));
		return -1;
	}
	return 0;
}

int tcp_send(int st,void* buffer)
{
	if(send(st,buffer,strlen(buffer),0)<0)
	{
		pmlog(SEND_FAIL);
		return -1;
	}
	//printf(">>>>>>>>>>>>>>>>>>>>>\n%s\n",(char*)buffer);
	return 0;
}

int tcp_recv(int st,void* buffer,size_t size)
{
	bzero(buffer,size);
	if(recv(st,buffer,size,0)<0)
	{
		pmlog(RECV_FAIL);
		return -1;
	}
	//printf("<<<<<<<<<<<<<<<<<<<<<<\n%s\n",(char*)buffer);
	return 0;
}

int tcp_close(int st)
{
	if(close(st)<0)
		return -1;
	return 0;
}

/* Subscription operations; */
int sub_init(const char* p)
{
	strcpy(_s_file,p);
	return 0;
}

NODE* sub_make(const char* p)
{
	return list_create((char*)p,strlen(p));
}

NODE* sub_get()
{
	char strsub[128];
	FILE* _f_subs;
	bzero(strsub,sizeof(strsub));
	if(!(_f_subs=fopen(_s_file,"r")))
	{
		_no_sub=1;
		pmlog(PM_NO_SUBSCRIBER);
		return 0;
	}
	/* The first node; */
	bzero(strsub,strlen(strsub));
	if(!fgets(strsub,sizeof(strsub),_f_subs))
	{
		_no_sub=1;
		pmlog(PM_NO_SUBSCRIBER);
		return 0;
	}
	if(strsub[strlen(strsub)-1]=='\n')
	{
		strsub[strlen(strsub)-1]=0;
	}
	NODE* slist=list_create(strsub,strlen(strsub));
	while(fgets(strsub,sizeof(strsub),_f_subs))
	{
		if(strsub[strlen(strsub)-1]=='\n')
		{
			strsub[strlen(strsub)-1]=0;
		}
		if(list_add(slist,strsub,strlen(strsub))<0)
		{
			pmlog(PM_SUBS_ERROR);
			return 0;
		}
	}
	fclose(_f_subs);
	_no_sub=0;
	return slist;
}

int sub_add(NODE* slist, const char* s)
{
	if(_no_sub)
		return 1;
	NODE* snode=slist;
	/* Check the subscriber; */
	while(snode)
	{
		/* The subscriber is already exisits; */
		if(!strcmp(s,snode->data))
			return -1;
		snode=snode->next;
	}
	if(list_add(slist,(char*)s,strlen(s))<0)
		return -1;
	
	return sub_write(slist);
}

int sub_del(NODE* slist, const char* s)
{
	int drt;
	if((drt=list_del(slist,(char*)s,strlen(s))<0))
		return -1;
	if(drt==1)
	{
		slist=0;
		_no_sub=1;
	}

	return sub_write(slist);
}

int sub_write(NODE* slist)
{
	NODE* node=slist;
	/* Write new linked list to file; */
	FILE* _f_subs;
	if(!(_f_subs=fopen(_s_file,"w")))
		return -1;
	if(_no_sub)
	{
		fclose(_f_subs);
		return 0;
	}
	while(node)
	{
		char* s=(char*)node->data;
		while(s[strlen(s)-1]!='>')
				s[strlen(s)-1]='\0';
		strcpy((char*)node->data,s);
		if(fprintf(_f_subs,"%s\n",(char*)node->data)<0)
		{
			pmlog(PM_FAIL_WRITE_SUBS);
			return -1;
		}
		node=node->next;
	}
	fclose(_f_subs);
	return 0;
}

/* To print usage info; opt is set when there is a wrong option given; */
void usage()
{
	fprintf(stdout,PM_EXE_HELP_C);
	fprintf(stdout,PM_EXE_HELP_R);
	fprintf(stdout,PM_EXE_HELP_V);
}

void pop3_process(ATBD* info, int pout, int tsleep)
{
	/* Infinite loop; Send STAT to check whether there are new mails or not. */
	while(1)
	{
		int spop;
		char pcmd[CMDMAX], str_rv[BUFMAX], str_mail[MAILMAX];
		if(tcp_init(&spop)<0)
			return;
		/* Connect to the POP3 server; */
		if(tcp_connect(spop,info)<0)
			return;
		/* Receive the welcome message; */
		if(tcp_recv(spop,str_rv,sizeof(str_rv))<0)
			return;
		int msize_f, mnum_f;
		int msize, mnum;
		/* Send USER #username; */
		sprintf(pcmd,POP3_USER,info->at_username);
		if(tcp_send(spop,pcmd)<0)
			return;
		if(tcp_recv(spop,pcmd,sizeof(pcmd))<0)
			return;
		if(pcmd[0]=='-')
		{
			pmlog(POP3_AUTH_FAIL);
			break;
		}
		
		/* Send PASS #password; */
		sprintf(pcmd,POP3_PASS,info->at_password);
		if(tcp_send(spop,pcmd)<0)
			return;
		if(tcp_recv(spop,pcmd,sizeof(pcmd))<0)
			return;
		
		/* Authorize failed; */
		if(pcmd[0]=='-')
		{
			pmlog(POP3_AUTH_FAIL);
			break;
		}
		/* Send STAT; */
		if(tcp_send(spop,POP3_STAT)<0)
			return;
		bzero(pcmd,sizeof(pcmd));
		if(tcp_recv(spop,pcmd,sizeof(pcmd))<0)
			return;
		/* Get the mail number and size of server; */
		sscanf(pcmd,POP3_STAT_STR,&mnum,&msize);
		/* Get the mail number and size of localhost; */
		if(mail_get(&mnum_f,&msize_f)<0 || mnum<mnum_f)
		{
			/* No mail stat in localhost; */
			mnum_f=msize_f=0;
			if(mail_set(mnum_f,msize_f)<0)
			{
				pmlog(PM_FILE_PERMISSION);
				return;
			}
		}
		/* Get the certain mails; */
		int i;
		for(i=mnum;i>mnum_f;i--)
		{
			bzero(str_mail,sizeof(str_mail));
			/* Retrieve the mail; */
			sprintf(pcmd,POP3_RETR,i);
			if(tcp_send(spop,pcmd)<0)
				return;
			bzero(str_rv,sizeof(str_rv));
			while(!strstr(str_mail,"\r\n.\r\n"))
			{
				if(tcp_recv(spop,str_rv,sizeof(str_rv))<0)
					return;
				strcat(str_mail,str_rv);
				
			}
			write(pout,str_mail,sizeof(str_mail));
		}
		/* Set the new mail stat to localhost; */
		if(mail_set(mnum,msize)<0)
		{
			pmlog(PM_FILE_PERMISSION);
			return;
		}
		/* Send QUIT; */
		if(tcp_send(spop,POP3_QUIT)<0)
			return;
		if(tcp_recv(spop,pcmd,sizeof(pcmd))<0)
			return;
		/* Close the connection; */
		close(spop);
		/* Sleep; */
		sleep(tsleep);
	}
}

void pop3_process_exec(const char* cfg_path,int pout)
{
	/* pop3 process; */
	char name[128];
	char mail[128];
	char hostname[128];
	int port,tsleep;
	char username[64];
	char password[64];
	/* Load configuration; */
	cfg_init(cfg_path);
	if(cfg_get("server","name",name)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("server","mail",mail)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("pop3","timeout",&tsleep)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}	
	if(cfg_get("pop3","server",hostname)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("pop3","port",&port)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("pop3","username",username)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("pop3","password",password)<0)
	{
		pmlog(POP3_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	cfg_exit();
	/* End of configuration loading; */
	ATBD info;
	init_atbd(&info,name,mail,hostname,port,username,password);
	pop3_process(&info,pout,tsleep);
	pmlog(SMTP_PROCESS_EXIT);
	/* Send SIGTERM to main process; */
	kill(getppid(),SIGTERM);
}

/* Retrieve the stat value of smtp server return; */
int smtp_stat(const char* strrt,const char* stat)
{
	if(strstr(strrt,stat))
		return 1;
	return 0;
}

void smtp_process(ATBD* info, int pin)
{	
	int ssmtp;
	if(tcp_init(&ssmtp)<0)
		return;
	if(tcp_connect(ssmtp,info)<0)
		return;
	/* Auth flag; */
	int sfirst=1;
	char scmd[CMDMAX], s_str[MAILMAX], s_mail[MAILMAX], s_mail_head[MAILMAX], s_mail_body[MAILMAX];
	if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
		return;
	/* Load subscribers' list; */
	NODE* slist=sub_get();
	/* Infinite loop; check the pipe to get mails; */
	while(1)
	{
		/* Read the pipe; This operation may blocks the process; */
		bzero(s_str,MAILMAX);
		if(read(pin,s_str,MAILMAX)<0)
		{
			pmlog(READ_FAIL);
			break;
		}
		/* Get a mail from pipe; */
		if(strlen(s_str))
		{
			if(sfirst)
			{
				sfirst=0;
				/* Say hello; */
				sprintf(scmd,SMTP_EHLO,info->at_hostname);
				if(tcp_send(ssmtp,scmd)<0)
					break;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					break;
				/* Send AUTH_LOGIN */
				if(tcp_send(ssmtp,SMTP_AUTH_LOGIN)<0)
					break;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					break;
				/* Send username and password; */
				sprintf(scmd,"%s\r\n",info->at_username_base64);
				if(tcp_send(ssmtp,scmd)<0)
					break;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					break;
				if(!smtp_stat(scmd,"334"))
				{
					pmlog(SMTP_LOGIN_REFUSE);
					break;
				}
				sprintf(scmd,"%s\r\n",info->at_password_base64);
				if(tcp_send(ssmtp,scmd)<0)
					break;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					break;
				if(!smtp_stat(scmd,"235"))
				{
					pmlog(SMTP_LOGIN_REFUSE);
					break;
				}
			}
			/* Send flag; */
			int issend=0;
			NODE* snode=slist;
			char sub[128];
			/* Check the mail; */
			/* Get the Sender's address; */
			char* sraw=strstr(s_str,"From: ");
			bzero(sub,sizeof(sub));
			sscanf(sraw,"From: %[^\r\n]",sub);
			if(!strstr(sub,"<"))
			{
				sprintf(scmd,"<%s>",sub);
				strcpy(sub,scmd);
			}
			else 
			{
				char* ss=sub;
				while(ss[0]!='<')
					ss++;
				strcpy(sub,ss);
			}
			/* Subscription operations; */
			/* A new subscriber; */
			if(strcasestr(s_str,PM_SUBJECT_SUB))
			{
				int radd;
				/* Add to subscriber's list; */
				if((radd=sub_add(slist,sub))>=0)
				{
					/* Make a new list; */
					if(radd==1)
					{
						slist=sub_make(sub);
						sub_write(slist);
						_no_sub=0;
					}
					/* Send welcome mail; */
					/* Send MAIL FROM; */
					sprintf(scmd,SMTP_MAIL_FROM,info->at_mail);
					if(tcp_send(ssmtp,scmd)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					/* RCPT TO; */
					sprintf(scmd,SMTP_RCPT_TO,sub);
					if(tcp_send(ssmtp,scmd)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					/* Send the mail; */
					if(tcp_send(ssmtp,SMTP_DATA)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					sprintf(s_mail,PM_SUBSCRIBED,sub,info->at_name);
					if(tcp_send(ssmtp,s_mail)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
				}
				continue;
			}
			/* Unscribe operation; */
			if(strcasestr(s_str,PM_SUBJECT_USUB))
			{
				/* Add to subscriber's list; */
				if(sub_del(slist,sub)==0)
				{
					/* Send unsubcribe mail; */
					/* Send MAIL FROM; */
					sprintf(scmd,SMTP_MAIL_FROM,info->at_mail);
					if(tcp_send(ssmtp,scmd)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					/* RCPT TO; */
					sprintf(scmd,SMTP_RCPT_TO,sub);
					if(tcp_send(ssmtp,scmd)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					/* Send the mail; */
					if(tcp_send(ssmtp,SMTP_DATA)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
					sprintf(s_mail,PM_USUBSCRIBE,sub,info->at_name);
					if(tcp_send(ssmtp,s_mail)<0)
						continue;
					if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
						continue;
				}
				continue;
			}
			/* Otherwise, check the mail to get the sender's information; */
			if(!_no_sub)
			{
				while(snode)
				{
					char sub_ck[128];
					sscanf((char*)snode->data,"<%[^>]",sub_ck);
					if(strcasestr(s_str,sub_ck))
					{
						/* The sender is in a subscriber; */ 
						issend=1;
						break;
					}
					snode=snode->next;
				}
			}
			
			if(issend)
			{
				issend=0;
				/* Send MAIL FROM; */
				sprintf(scmd,SMTP_MAIL_FROM,info->at_mail);
				if(tcp_send(ssmtp,scmd)<0)
					continue;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					continue;
				/* Load subscriber list; Send RCPT TO; */
				snode=slist;
				while(snode)
				{
					if(strcmp(sub,(char*)snode->data))
					{
						sprintf(scmd,SMTP_RCPT_TO,(char*)snode->data);
						if(tcp_send(ssmtp,scmd)<0)
							continue;
						if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
							continue;
						if(!smtp_stat(scmd,"250"))
						{
							pmlog(SMTP_RCPT_TO_ERROR);
							continue;
						}
					}
					snode=snode->next;
				}
				/* Send the mail; */
				if(tcp_send(ssmtp,SMTP_DATA)<0)
					continue;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					continue;
				/* Remove the +OK xxx; */
				char* ss=s_str;
				while(strncmp(ss,"From: ",strlen("From: ")))
					ss++;
				strcpy(s_str,ss);
				/* Add Reply-To; */
				sprintf(scmd,SMTP_REPLYTO,info->at_mail);
				char* sbody=strstr(s_str,"To: ");
				strcpy(s_mail_body,sbody);
				*sbody='\0';
				strcpy(s_mail_head,s_str);
				strcat(s_mail_head,scmd);
				sprintf(s_mail,SMTP_DATA_DATA,s_mail_head,s_mail_body);
				if(tcp_send(ssmtp,s_mail)<0)
					continue;
				if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
					continue;
				if(!smtp_stat(scmd,"250"))
				{
					pmlog(SMTP_SEND_FAIL);
					continue;
				}
			}
			/* Send NOOP; */
			if(tcp_send(ssmtp,SMTP_NOOP)<0)
				break;
			if(tcp_recv(ssmtp,scmd,sizeof(scmd))<0)
				break;
		}
	}
	/* Clear subscribers' list; */
	list_clear(slist);
}

void smtp_process_exec(const char* cfg_path,const char* subs_path,int pin)
{
	/* smtp process; */
	char name[128];
	char mail[128];
	char hostname[128];
	int port;
	char username[64];
	char password[64];
	int rt;
	/* Load configuration; */
	cfg_init(cfg_path);
	if(cfg_get("server","name",name)<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("server","mail",mail)<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if((rt=cfg_get("smtp","server",hostname))<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("smtp","port",&port)<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("smtp","username",username)<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	if(cfg_get("smtp","password",password)<0)
	{
		pmlog(SMTP_CFG_ERROR);
		exit(EXIT_FAILURE);
	}
	cfg_exit();
	/* End of configuration loading;*/
	ATBD info;
	init_atbd(&info,name,mail,hostname,port,username,password);
	smtp_process(&info,pin);
	pmlog(SMTP_PROCESS_EXIT);
	/* Send SIGTERM to main process; */
	kill(getppid(),SIGTERM);
}

void sigkill_perform(int signum)
{
	/* Kill all process which have the same gid; */
	if(kill(0,SIGKILL)<0)
		exit(EXIT_FAILURE);
}

int main(int argc, char** argv)
{
	/* frun - run flag; fver - show version; errcfg - configuration error; */
	int frun, fver, cn, errcfg, fc;
	/* Process IDs, pme is the main process ID; */
	pid_t ppop3,psmtp,pme;
	int pp[2];
	char cfg_path[PATHMAX];
	char log_path[PATHMAX];
	char subs_path[PATHMAX];
	char mstat_path[PATHMAX];
	char* pm_cfg=getenv("PM_CFG");
	pme=getpid();
	frun = fver = fc = 0;
	/* No argument; Show help and exit; */
	if(argc==1)
	{
		usage();
		exit(EXIT_FAILURE);
	}
	while((cn=getopt(argc, argv, "rc:vh")) != -1)
	{
		switch(cn)
		{
			case 'v':
				fver=1;
				break;
			case 'r':
				frun=1;
				break;
			case 'c':
				bzero(cfg_path,PATHMAX);
				sprintf(cfg_path,"%s/%s/%s",pm_cfg,optarg,"postmorerc");
				sprintf(log_path,"%s/%s/%s",pm_cfg,optarg,"log");
				sprintf(subs_path,"%s/%s/%s",pm_cfg,optarg,"subs");
				sprintf(mstat_path,"%s/%s/%s",pm_cfg,optarg,"mstat");
				if(cfg_init(cfg_path)!=0)
					errcfg=1;
				fc=1;
				break;
			case'?':
			default:
				usage();
				exit(EXIT_FAILURE);
				break;

		}
	}
	cfg_exit();
	if(errcfg)
	{
		exit(EXIT_FAILURE);
	}
	if(frun && fc)
	{
		/* Install signal performance; */
		signal(SIGTERM,sigkill_perform);
		signal(SIGINT,sigkill_perform);
		/* Initalize log; */
		pmlog_init(log_path);
		/* Initalize subscribers' list; */
		sub_init(subs_path);
		/* Initalize mail stat; */
		mail_init(mstat_path);
		/* Create a pipe; */
		if(pipe(pp)<0)
		{
			pmlog(PM_PIPE_FAIL);
			exit(EXIT_FAILURE);
		}
		/* Start the pop3 process; */
		ppop3=fork();
		if(ppop3==0)
		{
			pop3_process_exec(cfg_path,pp[1]);
		}
		else
		{
			/* Exception, can not create new process; */
			if(ppop3<0)
			{
				pmlog(FORK_FAIL);
				exit(EXIT_FAILURE);
			}
			else 
			{
				/* Start the smtp process; */
				psmtp=fork();
				if(psmtp==0)
				{
					smtp_process_exec(cfg_path,subs_path,pp[0]);
				}
				else 
				{
					/* Exception, can not create new process; */
					if(psmtp<0)
					{
						pmlog(FORK_FAIL);
						exit(EXIT_FAILURE);
					}
					else 
					{
						/* Block the program; */
						while(1)
						{
							sleep(1);
						}
					}
				}
			}
		
		}
	}

	if(fver)
		fprintf(stdout,PMEXEVERSION,__DATE__);
	
	return 0;
}
